﻿using System;
using System.Collections;
using System.Globalization;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;

namespace Practical.SharePoint.Base
{
    public static class SPExtensions
    {
        public static readonly string PropertyPrefix = typeof (SPExtensions).Namespace;
        
        private const string _parameterCanNotBeAnEmptyString = "Parameter can not be an empty string";

        public static string GetCustomProperty(this Hashtable hashtable, string propertyname)
        {
            if (hashtable == null)
            {
                throw new ArgumentNullException("hashtable");
            }

            if (propertyname == null)
            {
                throw new ArgumentNullException("propertyname");
            }

            if (string.IsNullOrEmpty(propertyname))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString, "propertyname");
            }

            string internalPropertyName = PropertyPrefix + propertyname;
            string returnvalue = hashtable[internalPropertyName] == null ? "" : hashtable[internalPropertyName].ToString();
            return returnvalue;
        }

        public static string GetCustomProperty(this SPPropertyBag propertybag, string propertyname)
        {
            if (propertybag == null)
            {
                throw new ArgumentNullException("propertybag");
            }

            if (propertyname == null)
            {
                throw new ArgumentNullException("propertyname");
            }

            if (string.IsNullOrEmpty(propertyname))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString, "propertyname");
            }

            string internalPropertyName = PropertyPrefix + propertyname;
            string returnvalue = propertybag[internalPropertyName] == null ? string.Empty : propertybag[internalPropertyName].ToString(CultureInfo.InvariantCulture);
            return returnvalue;
        }

        public static void SetCustomProperty(this Hashtable hashtable, string propertyname, string propertyvalue)
        {
            if (hashtable == null)
            {
                throw new ArgumentNullException("hashtable");
            }

            if (propertyname == null)
            {
                throw new ArgumentNullException("propertyname");
            }

            if (propertyvalue == null)
            {
                throw new ArgumentNullException("propertyvalue");
            }

            if (string.IsNullOrEmpty(propertyname))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString, "propertyname");
            }

            if (string.IsNullOrEmpty(propertyvalue))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString, "propertyvalue");
            }

            string internalPropertyName = PropertyPrefix + propertyname;

            if (hashtable[internalPropertyName] == null)
            {
                hashtable.Add(internalPropertyName, propertyvalue);
            }
            else
            {
                hashtable[internalPropertyName] = propertyvalue;
            }
        }

        public static void SetCustomProperty(this SPPropertyBag propertybag, string propertyname, string propertyvalue)
        {
            if (propertybag == null)
            {
                throw new ArgumentNullException("propertybag");
            }

            if (propertyname == null)
            {
                throw new ArgumentNullException("propertybag");
            }

            if (propertyvalue == null)
            {
                throw new ArgumentNullException("propertyvalue");
            }

            if (string.IsNullOrEmpty(propertyname))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString,"propertyname");
            }

            if (string.IsNullOrEmpty(propertyvalue))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString, "propertyvalue");
            }

            string internalPropertyName = PropertyPrefix + propertyname;

            if (propertybag[internalPropertyName] == null)
            {
                propertybag.Add(internalPropertyName, propertyvalue);
            }
            else
            {
                propertybag[internalPropertyName] = propertyvalue;
            }
        }

        public static bool ContainsCustomProperty(this Hashtable hashtable, string propertyname)
        {
            if (hashtable == null)
            {
                throw new ArgumentNullException("hashtable");
            }

            if (propertyname == null)
            {
                throw new ArgumentNullException("propertyname");
            }
            
            if (string.IsNullOrEmpty(propertyname))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString,"propertyname");
            }
            string internalPropertyName = PropertyPrefix + propertyname;
            return hashtable.Contains(internalPropertyName);
        }

        public static bool ContainsCustomProperty(this SPPropertyBag propertybag, string propertyname)
        {
            if (propertybag == null)
            {
                throw new ArgumentNullException("propertybag");
            }

            if (propertyname == null )
            {
                throw new ArgumentNullException("propertyname");
            }

            if (string.IsNullOrEmpty(propertyname))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString,"propertyname");
            }

            string internalPropertyName = PropertyPrefix + propertyname;
            return propertybag.ContainsKey(internalPropertyName);
        }

        public static Uri GetContextResolvedUri(this SPContext current, string basePath)
        {
            if (current != null
                &&
                current.Web != null)
            {
                return new Uri(current.Web.Url + basePath);
            }
            return new Uri(basePath);
        }

        public static void AddListEventReceiver(Type eventReceiverType, SPList spList, SPEventReceiverType spEventReceiverType, int eventReceiverSequenceNumber)
        {
            if (eventReceiverType == null)
            {
                throw new ArgumentNullException("eventReceiverType");
            }

            if (spList == null)
            {
                throw new ArgumentNullException("spList");
            }

            int receivers = spList.EventReceivers.Count;
            bool isAddedReceiverExist = false;
            for (var i = 0; i < receivers; i++)
            {
                SPEventReceiverDefinition eventReceiver = spList.EventReceivers[i];
                if (eventReceiver.Class == eventReceiverType.ToString() && eventReceiver.Type == spEventReceiverType)
                {
                    isAddedReceiverExist = true;
                    break;
                }
            }
            if (!isAddedReceiverExist)
            {
                SPEventReceiverDefinition spEventReceiverDefinition = spList.EventReceivers.Add();
                spEventReceiverDefinition.Name = string.Format(CultureInfo.InstalledUICulture,"{0}:{1}", "DCP.CAW.SharePoint", spEventReceiverType);
                spEventReceiverDefinition.Assembly = eventReceiverType.Assembly.FullName;
                spEventReceiverDefinition.Class = eventReceiverType.ToString();
                spEventReceiverDefinition.Type = spEventReceiverType;
                spEventReceiverDefinition.HostId = spList.ID;
                spEventReceiverDefinition.HostType = SPEventHostType.List;
                spEventReceiverDefinition.SequenceNumber = eventReceiverSequenceNumber;
                spEventReceiverDefinition.Update();
                spList.Update();
            }
        }

        public static void RemoveListEventReceiver(Type eventReceiverType, SPList spList, SPEventReceiverType spEventReceiverType)
        {
            if (eventReceiverType == null)
            {
                throw new ArgumentNullException("eventReceiverType");
            }

            if (spList == null)
            {
                throw new ArgumentNullException("spList");
            }

            SPEventReceiverDefinition spEventReceiverDefinition = null;
            foreach (SPEventReceiverDefinition eventReceiver in spList.EventReceivers)
            {
                if (
                    eventReceiver.Class == eventReceiverType.ToString()
                    &&
                    eventReceiver.Type == spEventReceiverType
                    )
                {
                    spEventReceiverDefinition = eventReceiver;
                    break;
                }
            }

            if (spEventReceiverDefinition != null)
            {
                spEventReceiverDefinition.Delete();
                spList.Update();
            }
        }

        public static void AddEventReceiver(Type eventReceiverType, SPContentType spContentType, SPEventReceiverType spEventReceiverType, int eventReceiverSequenceNumber)
        {
            if (eventReceiverType == null)
            {
                throw new ArgumentNullException("eventReceiverType");
            }

            if (spContentType == null)
            {
                throw new ArgumentNullException("spContentType");
            }

            int receivers = spContentType.EventReceivers.Count;
            bool isAddedReceiverExist = false;
            for (var i = 0; i < receivers; i++)
            {
                SPEventReceiverDefinition eventReceiver = spContentType.EventReceivers[i];
                if (eventReceiver.Class == eventReceiverType.ToString() && eventReceiver.Type == spEventReceiverType)
                {
                    isAddedReceiverExist = true;
                    break;
                }
            }
            if (!isAddedReceiverExist)
            {
                SPEventReceiverDefinition spEventReceiverDefinition = spContentType.EventReceivers.Add();
                spEventReceiverDefinition.Name = string.Format(CultureInfo.InvariantCulture,"{0}:{1}", "DCP.CAW.SharePoint", spEventReceiverType);
                spEventReceiverDefinition.Assembly = eventReceiverType.Assembly.FullName;
                spEventReceiverDefinition.Class = eventReceiverType.ToString();
                spEventReceiverDefinition.Type = spEventReceiverType;
                spEventReceiverDefinition.HostType = SPEventHostType.ContentType;
                spEventReceiverDefinition.SequenceNumber = eventReceiverSequenceNumber;
                spEventReceiverDefinition.Synchronization = SPEventReceiverSynchronization.Synchronous;
                spEventReceiverDefinition.Update();
            }
        }

        public static void RemoveEventReceiver(Type eventReceiverType, SPContentType spContentType, SPEventReceiverType spEventReceiverType)
        {
            if (eventReceiverType == null)
            {
                throw new ArgumentNullException("eventReceiverType");
            }

            if (spContentType == null)
            {
                throw new ArgumentNullException("spContentType");
            }

            SPEventReceiverDefinition spEventReceiverDefinition = null;
            foreach (SPEventReceiverDefinition eventReceiver in spContentType.EventReceivers)
            {
                if (
                    eventReceiver.Class == eventReceiverType.ToString()
                    &&
                    eventReceiver.Type == spEventReceiverType
                    )
                {
                    spEventReceiverDefinition = eventReceiver;
                    break;
                }
            }

            if (spEventReceiverDefinition != null)
            {
                spEventReceiverDefinition.Delete();
            }
        }

        public static void DeactivateRelatedFeature(SPWeb spWeb, string featureId)
        {
            if (spWeb == null)
            {
                throw new ArgumentNullException("spWeb");
            }

            if (featureId == null)
            {
                throw new ArgumentNullException("featureId");
            }

            if (string.IsNullOrEmpty(featureId))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString, "featureId");
            }

            SPFeatureDefinition identifiedFeature =
                spWeb.Site.WebApplication.Farm.FeatureDefinitions.FirstOrDefault(
                    f => f.Id == new Guid(featureId)
                         && f.Scope == SPFeatureScope.Web);

            if (identifiedFeature != null && spWeb.Features[identifiedFeature.Id] != null)
            {
                spWeb.AllowUnsafeUpdates = true;
                spWeb.Features.Remove(identifiedFeature.Id);
                spWeb.AllowUnsafeUpdates = false;
            }
        }

        public static void ActivateRelatedFeature(SPWeb spWeb, string featureId)
        {
            if (spWeb == null)
            {
                throw new ArgumentNullException("spWeb");
            }

            if (featureId == null)
            {
                throw new ArgumentNullException("featureId");
            }

            if (string.IsNullOrEmpty(featureId))
            {
                throw new ArgumentException(_parameterCanNotBeAnEmptyString, "featureId");
            }

            SPFeatureDefinition identifiedFeature =
                spWeb.Site.WebApplication.Farm.FeatureDefinitions.FirstOrDefault(
                    f => f.Id == new Guid(featureId)
                         && f.Scope == SPFeatureScope.Web);

            if (identifiedFeature != null && spWeb.Features[identifiedFeature.Id] == null)
            {
                spWeb.AllowUnsafeUpdates = true;
                spWeb.Features.Add(identifiedFeature.Id);
                spWeb.AllowUnsafeUpdates = true;
                spWeb.Update();
            }
        }

        public static bool IsFunctionalityEnabled(string value)
        {
            bool result;
            return bool.TryParse(value, out result) && result;
        }
    }
}
